﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Oracle.EntityFrameworkCore.Infrastructure;
using Pomelo.EntityFrameworkCore.MySql.Storage;
using ShardingCore;
using ShardingCore.Core.DbContextCreator;
using ShardingWTM.Models;
using sharecore;
using System;
using WalkingTec.Mvvm.Core;

namespace ShardingWTM
{
    public static class ShardingExtensions
    {
        public static readonly ILoggerFactory efLogger = LoggerFactory.Create(builder =>
        {
            builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information).AddConsole();
        });

        public static void AddShareingWTM(this IServiceCollection services, IConfiguration config)
        {
            string Version = null;

            var cs = config.Get<Configs>() ?? new Configs();
            string connectionStr = cs.ConnectionStrings[0].Value;
            DBTypeEnum DBType = cs.DbType;

            services.AddScoped<DataContext>(sp =>
            {
                var optionsBuilder = new DbContextOptionsBuilder<FrameworkContext>();

                switch (DBType)
                {
                    case DBTypeEnum.SqlServer:
                        optionsBuilder.UseSqlServer(connectionStr).UseLoggerFactory(efLogger);
                        break;
                    case DBTypeEnum.MySql:
                        {
                            optionsBuilder.UseMySql(connectionStr, (Action<MySqlDbContextOptionsBuilder>)delegate (MySqlDbContextOptionsBuilder mySqlOptions)
                            {
                                if (!string.IsNullOrEmpty(Version))
                                {
                                    mySqlOptions.ServerVersion(Version);
                                }
                            }).UseLoggerFactory(efLogger);
                            break;
                        }
                    case DBTypeEnum.PgSql:
                        optionsBuilder.UseNpgsql(connectionStr).UseLoggerFactory(efLogger);
                        break;
                    case DBTypeEnum.Memory:
                        optionsBuilder.UseInMemoryDatabase(connectionStr).UseLoggerFactory(efLogger);
                        break;
                    case DBTypeEnum.SQLite:
                        optionsBuilder.UseSqlite(connectionStr).UseLoggerFactory(efLogger);
                        break;
                    case DBTypeEnum.Oracle:
                        optionsBuilder.UseOracle(connectionStr, delegate (OracleDbContextOptionsBuilder option)
                        {
                            if (!string.IsNullOrEmpty(Version))
                                option.UseOracleSQLCompatibility(Version);
                            else
                                option.UseOracleSQLCompatibility("11");
                        }).UseLoggerFactory(efLogger);
                        break;
                }

                optionsBuilder.UseSharding<DataContext>();
                return new DataContext(optionsBuilder.Options);
            });
            services.AddShardingConfigure<DataContext>()
                .AddEntityConfig(o =>
                {
                    o.CreateShardingTableOnStart = true;
                    o.EnsureCreatedWithOutShardingTable = true;

                    #region Use ShardingTableRoute

                    o.AddShardingTableRoute<MessageLogRoute>();

                    #endregion

                })
                .AddConfig(o =>
                {
                    o.AddDefaultDataSource("ds0", connectionStr);
                    o.ConfigId = "c1";
                    o.UseShardingQuery((conn, optionsBuilder) =>
                    {
                        //optionsBuilder.UseMySql(conn, new MySqlServerVersion(new Version())).UseLoggerFactory(efLogger);
                        switch (DBType)
                        {
                            case DBTypeEnum.SqlServer:
                                optionsBuilder.UseSqlServer(connectionStr).UseLoggerFactory(efLogger);
                                break;
                            case DBTypeEnum.MySql:
                                {
                                    optionsBuilder.UseMySql(connectionStr, (Action<MySqlDbContextOptionsBuilder>)delegate (MySqlDbContextOptionsBuilder mySqlOptions)
                                    {
                                        if (!string.IsNullOrEmpty(Version))
                                        {
                                            mySqlOptions.ServerVersion(Version);
                                        }
                                    }).UseLoggerFactory(efLogger);
                                    break;
                                }
                            case DBTypeEnum.PgSql:
                                optionsBuilder.UseNpgsql(connectionStr).UseLoggerFactory(efLogger);
                                break;
                            case DBTypeEnum.Memory:
                                optionsBuilder.UseInMemoryDatabase(connectionStr).UseLoggerFactory(efLogger);
                                break;
                            case DBTypeEnum.SQLite:
                                optionsBuilder.UseSqlite(connectionStr).UseLoggerFactory(efLogger);
                                break;
                            case DBTypeEnum.Oracle:
                                optionsBuilder.UseOracle(connectionStr, delegate (OracleDbContextOptionsBuilder option)
                                {
                                    if (!string.IsNullOrEmpty(Version))
                                        option.UseOracleSQLCompatibility(Version);
                                    else
                                        option.UseOracleSQLCompatibility("11");
                                }).UseLoggerFactory(efLogger);
                                break;
                        }
                    });
                    o.UseShardingTransaction((conn, optionsBuilder) =>
                    {
                        //build.UseMySql(conn, new MySqlServerVersion(new Version())).UseLoggerFactory(efLogger)
                        switch (DBType)
                        {
                            case DBTypeEnum.SqlServer:
                                optionsBuilder.UseSqlServer(connectionStr).UseLoggerFactory(efLogger);
                                break;
                            case DBTypeEnum.MySql:
                                {
                                    optionsBuilder.UseMySql(connectionStr, (Action<MySqlDbContextOptionsBuilder>)delegate (MySqlDbContextOptionsBuilder mySqlOptions)
                                    {
                                        if (!string.IsNullOrEmpty(Version))
                                        {
                                            mySqlOptions.ServerVersion(Version);
                                        }
                                    }).UseLoggerFactory(efLogger);
                                    break;
                                }
                            case DBTypeEnum.PgSql:
                                optionsBuilder.UseNpgsql(connectionStr).UseLoggerFactory(efLogger);
                                break;
                            case DBTypeEnum.Memory:
                                optionsBuilder.UseInMemoryDatabase(connectionStr).UseLoggerFactory(efLogger);
                                break;
                            case DBTypeEnum.SQLite:
                                optionsBuilder.UseSqlite(connectionStr).UseLoggerFactory(efLogger);
                                break;
                            case DBTypeEnum.Oracle:
                                optionsBuilder.UseOracle(connectionStr, delegate (OracleDbContextOptionsBuilder option)
                                {
                                    if (!string.IsNullOrEmpty(Version))
                                        option.UseOracleSQLCompatibility(Version);
                                    else
                                        option.UseOracleSQLCompatibility("11");
                                }).UseLoggerFactory(efLogger);
                                break;
                        }
                    });
                    //无需下面这部分内容
                    //o.ReplaceTableEnsureManager(sp => {
                    //            return new MySqlTableEnsureManager<DataContext>();
                    //});
                }).EnsureConfig();

            services.Replace(ServiceDescriptor.Singleton<IDbContextCreator<DataContext>, WTMDbContextCreator<DataContext>>());
            services.Replace(ServiceDescriptor.Scoped<IDataContext>(sp =>
            {
                return sp.GetService<DataContext>();
            }));

        }
    }
}
